home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 26
/
Cream of the Crop 26.iso
/
program
/
vol16n13.zip
/
ATLCTL.ZIP
/
AtlEditCtl.h
< prev
next >
Wrap
C/C++ Source or Header
|
1997-01-29
|
17KB
|
601 lines
///////////////////////////////////////////////////////////////////////////////
// PC Magazine ActiveX Validated Edit Control
// First appeared in PC Magazine, US Edition, ...
//
// Written by John Lam
// AtlEditCtl.h : Declaration of the CAtlEditCtl
#ifndef __ATLEDITCTL_H_
#define __ATLEDITCTL_H_
#include "resource.h" // main symbols
#include "CPAtlEdit10.h" // our CProxy_AtlEditCtlEvents implementation
// Declarations for our system OLE_COLOR values
const int OLE_COLOR_WINDOW_BACKGROUND = 0x80000005;
const int OLE_COLOR_WINDOW_TEXT = 0x80000008;
/////////////////////////////////////////////////////////////////////////////
// CAtlEditCtl
class ATL_NO_VTABLE CAtlEditCtl :
public CComObjectRootEx<CComObjectThreadModel>,
public CComCoClass<CAtlEditCtl, &CLSID_AtlEditCtl>,
public CComControl<CAtlEditCtl>,
public CStockPropImpl<CAtlEditCtl, IAtlEditCtl, &IID_IAtlEditCtl, &LIBID_ATLEDIT10Lib>,
// We changed parameter 2 from NULL in the default implementation to
// DIID_AtlEditCtlEvents to specify the outgoing interface for our events
public IProvideClassInfo2Impl<&CLSID_AtlEditCtl, &DIID__AtlEditCtlEvents, &LIBID_ATLEDIT10Lib>,
public IPersistStreamInitImpl<CAtlEditCtl>,
public IPersistStorageImpl<CAtlEditCtl>,
public IQuickActivateImpl<CAtlEditCtl>,
public IOleControlImpl<CAtlEditCtl>,
public IOleObjectImpl<CAtlEditCtl>,
public IOleInPlaceActiveObjectImpl<CAtlEditCtl>,
public IViewObjectExImpl<CAtlEditCtl>,
public IOleInPlaceObjectWindowlessImpl<CAtlEditCtl>,
public IDataObjectImpl<CAtlEditCtl>,
public ISpecifyPropertyPagesImpl<CAtlEditCtl>,
// We added these two additional classes to our inheritance list
// so that our control can now support outgoing events
public CProxy_AtlEditCtlEvents<CAtlEditCtl>,
public IConnectionPointContainerImpl<CAtlEditCtl>,
// This line is required for VB5
public IPropertyNotifySinkCP<CAtlEditCtl>
{
public:
CContainedWindow m_ctlEdit;
CAtlEditCtl() :
m_ctlEdit(_T("Edit"), this, 1), m_hFontPrev( 0 )
{
m_bWindowOnly = TRUE;
}
DECLARE_REGISTRY_RESOURCEID(IDR_ATLEDITCTL)
BEGIN_COM_MAP(CAtlEditCtl)
COM_INTERFACE_ENTRY(IAtlEditCtl)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY_IMPL(IViewObjectEx)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject2, IViewObjectEx)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject, IViewObjectEx)
// COM_INTERFACE_ENTRY_IMPL(IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleInPlaceObject, IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleWindow, IOleInPlaceObjectWindowless)
COM_INTERFACE_ENTRY_IMPL(IOleInPlaceActiveObject)
COM_INTERFACE_ENTRY_IMPL(IOleControl)
COM_INTERFACE_ENTRY_IMPL(IOleObject)
COM_INTERFACE_ENTRY_IMPL(IQuickActivate)
COM_INTERFACE_ENTRY_IMPL(IPersistStorage)
COM_INTERFACE_ENTRY_IMPL(IPersistStreamInit)
COM_INTERFACE_ENTRY_IMPL(ISpecifyPropertyPages)
COM_INTERFACE_ENTRY_IMPL(IDataObject)
COM_INTERFACE_ENTRY(IProvideClassInfo)
COM_INTERFACE_ENTRY(IProvideClassInfo2)
// We added this line to add the IConnectionPointContainer interface
// to the list of interfaces that the container can QI for
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()
BEGIN_PROPERTY_MAP(CAtlEditCtl)
PROP_ENTRY( "Back Color", DISPID_BACKCOLOR, CLSID_StockColorPage )
PROP_ENTRY( "Fore Color", DISPID_FORECOLOR, CLSID_StockColorPage )
PROP_ENTRY( "Error Color", 0, CLSID_StockColorPage )
PROP_PAGE(CLSID_StockColorPage)
END_PROPERTY_MAP()
// We add a connection point map so that ATL (specifically, IConnectionPointContainerImpl)
// knows about our outgoing interface. We also needed to add the IPropertyNotifySink
// outgoing interface so that the control works properly in VB5.
BEGIN_CONNECTION_POINT_MAP(CAtlEditCtl)
CONNECTION_POINT_ENTRY(DIID__AtlEditCtlEvents)
CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
END_CONNECTION_POINT_MAP()
BEGIN_MSG_MAP(CAtlEditCtl)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
MESSAGE_HANDLER(WM_CREATE, OnCreate)
MESSAGE_HANDLER(WM_SETFOCUS, OnOleControlSetFocus)
MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
// Our message handler to tell the edit control what colors to
// use for the foreground and background colors
MESSAGE_HANDLER(WM_CTLCOLOREDIT, OnCtlColorEdit)
ALT_MSG_MAP(1)
// We have to add these message handlers for the set focus and
// lost (kill) focus messages. The lost focus handler fires the
// validation event.
MESSAGE_HANDLER(WM_KILLFOCUS, OnSubclassKillFocus)
// MESSAGE_HANDLER(WM_CHAR, OnChar)
END_MSG_MAP()
///////////////////////////////////////////////////////////////////////////
// Helper functions
// This is a helper function that handles changing the edit control's font
// when the font changes.
HRESULT OnFontChanged()
{
HFONT hFont;
// We only change the font if we are in run-time mode (i.e. there is a
// edit control window - which doesn't exist at design time)
if( IsWindow( m_ctlEdit ) )
{
if( m_Font == NULL )
{
// A serious failure. Make sure that we don't have a selected font
// in our control
m_ctlEdit.SendMessage( WM_SETFONT, 0, 0 );
m_hFontPrev = 0;
return E_FAIL;
}
if( FAILED( m_Font->get_hFont( &hFont ) ) )
return E_FAIL;
// Addref this font
m_Font->AddRefHfont( hFont );
m_ctlEdit.SendMessage( WM_SETFONT, (WPARAM) hFont, 0 );
// See if there was a previous font
if( m_hFontPrev != NULL )
{
// Yes there was, so let's release that font from our font object
m_Font->ReleaseHfont( hFont );
m_hFontPrev = hFont;
}
}
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
// General windows message handlers
// Pass along the appropriate control messages to the default windows
// message handler
/*
LRESULT OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if( static_cast< TCHAR >( wParam ) == VK_TAB )
{
CComQIPtr <IOleControlSite, &IID_IOleControlSite> spSite(m_spClientSite);
MSG msg;
HRESULT hr;
msg.hwnd = m_ctlEdit;
msg.message = WM_KEYDOWN;
msg.wParam = static_cast< WPARAM >( VK_TAB );
msg.lParam = 0;
BOOL bShift = (GetKeyState(VK_SHIFT) < 0);
BOOL bCtrl = (GetKeyState(VK_CONTROL) < 0);
BOOL bAlt = (GetKeyState(VK_MENU) < 0);
hr = spSite->TranslateAccelerator( &msg, (short)(bShift + (bCtrl << 1) + (bAlt << 2)) );
// MessageBox( "tabbed me", 0, 0 );
// return m_ctlEdit.DefWindowProc( WM_CHAR, wParam, lParam );
return 0;
}
bHandled = FALSE;
return 0;
}
*/
// We must force the focus into our contained control when we ourselves receive
// the focus.
LRESULT OnOleControlSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if( m_ctlEdit )
m_ctlEdit.SetFocus();
return 0;
}
// This message handler for WM_KILLFOCUS fires the controls Validate event
// The edit control assumes success for the validation event. Therefore,
// if the user does not implement the Validate event in his control, the
// control will behave just like a regular edit control.
LRESULT OnSubclassKillFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
int Length;
LPTSTR szText;
VARIANT_BOOL Valid = TRUE; // assume success
Length = m_ctlEdit.GetWindowTextLength();
szText = (LPTSTR)_alloca( ( Length + 1 ) * sizeof( TCHAR ) );
m_ctlEdit.GetWindowText( szText, Length + 1 );
CComBSTR Text = szText;
Validate( Text, &Valid );
if( Valid )
{
m_clrBackColor = m_clrCurrentBackColor;
}
else
{
m_clrCurrentBackColor = m_clrBackColor;
m_clrBackColor = m_clrErrorColor;
}
FireViewChange();
bHandled = FALSE; // Call the default handler for WM_KILLFOCUS
return 0;
}
// We modify some of the code in this function to make sure that our
// edit control is a multiline edit control with a 3D look (WS_EX_CLIENTEDGE)
LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
USES_CONVERSION;
RECT rc;
GetWindowRect(&rc);
rc.right -= rc.left;
rc.bottom -= rc.top;
rc.top = rc.left = 0;
// Make sure we destroy the child window if necessary ... or reset the
// child window's window handle to 0. A bug in an early version of ATL
// caused this window handle to NOT be reset to 0 when its parent
// (the control window) is itself destroyed in the
// IOleInPlaceObject::UIDeactivate handler
if( m_ctlEdit.m_hWnd )
if( IsWindow( m_ctlEdit ) )
m_ctlEdit.DestroyWindow();
else
m_ctlEdit.m_hWnd = 0;
// Make sure that we create the Edit control with the appropriate window
// style bits set.
m_ctlEdit.Create( m_hWnd, rc, NULL, WS_CHILD | WS_VISIBLE |
ES_AUTOVSCROLL | ES_MULTILINE, WS_EX_CLIENTEDGE );
// Initialize our edit control's window text with our Text property
if( IsWindow( m_ctlEdit ) )
m_ctlEdit.SetWindowText( OLE2T( m_bstrText ) );
OnFontChanged();
return 0;
}
// Our custom message handler to set the foreground and background
// colors for the edit control
LRESULT OnCtlColorEdit(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// Translate OLE_COLOR's back into Win32 COLORREF's
COLORREF clrBack, clrFore;
if( FAILED( OleTranslateColor( m_clrBackColor, m_hPalette, &clrBack ) ) )
OleTranslateColor( OLE_COLOR_WINDOW_BACKGROUND, m_hPalette, &clrBack );
if( FAILED( OleTranslateColor( m_clrForeColor, m_hPalette, &clrFore ) ) )
OleTranslateColor( OLE_COLOR_WINDOW_TEXT, m_hPalette, &clrFore );
::SetTextColor( (HDC)wParam, clrFore );
::SetBkColor( (HDC)wParam, clrBack );
return (LRESULT)::CreateSolidBrush( clrBack );
}
///////////////////////////////////////////////////////////////////////////
// Persistence handlers
// Handle the IPersistStreamInit::InitNew function call from our control's
// container. This function is called whenever a new instance of a control
// is created. We use this function to setup our control's ambient properties
STDMETHOD(InitNew)()
{
OLE_COLOR clrBack, clrFore;
// Setup default colors for our foreground and background colors
m_clrBackColor = OLE_COLOR_WINDOW_BACKGROUND;
m_clrForeColor = OLE_COLOR_WINDOW_TEXT;
if( SUCCEEDED( GetAmbientBackColor( clrBack ) ) )
m_clrBackColor = clrBack;
if( SUCCEEDED( GetAmbientForeColor( clrFore ) ) )
m_clrForeColor = clrFore;
// Our default error color is RED
m_clrErrorColor = RGB( 255, 0, 0 );
GetAmbientPalette( m_hPalette );
// Get a copy of the container's ambient font object
// I don't implement a notification handler for what happens when the
// container's ambient font CHANGES. This exercise is left to the reader.
HRESULT hr;
CComPtr<IFont> Font;
if( SUCCEEDED( GetAmbientFont( &Font ) ) )
{
// Make sure that our current font property is not holding onto
// some font
if( m_Font )
m_Font.Release();
hr = Font->Clone( &m_Font );
if( FAILED( hr ) )
return hr;
}
else
{
// You might want to add code to create your own font object
// if you can't get the ambient font from the container
}
return S_OK;
}
// We must handle the persistence of the Text and Font properties ourselves.
// This is due to the hybrid behavior of the control in design vs. run
// time. We do not wish to persist the run-time contents of the control!
STDMETHOD(Load)(LPSTREAM pStm)
{
HRESULT hr;
// Load the stock properties ( the color properties in this case )
// which have default persistance implementations.
hr = IPersistStreamInitImpl<CAtlEditCtl>::Load( pStm );
if( FAILED( hr ) )
return hr;
// Create our Font object from persistant storage
CComPtr< IFont > Font;
if( SUCCEEDED( OleLoadFromStream( pStm, IID_IFont, (void**)&Font ) ) )
m_Font = Font;
// Load our text property from persistant storage
return m_bstrText.ReadFromStream( pStm );
}
STDMETHOD(Save)(LPSTREAM pStm, BOOL fClearDirty)
{
HRESULT hr;
hr = IPersistStreamInitImpl<CAtlEditCtl>::Save( pStm, fClearDirty );
if( FAILED( hr ) )
return hr;
// Save our font object to persistant storage
// This is a nice demonstration of the CComQIPtr. In the constructor
// call, pObjStream QI's for the IID_IPersistStream interface from the
// m_Font pointer to the font object's IFont interface. Saves a line
// of code.
CComQIPtr< IPersistStream, &IID_IPersistStream > pObjStream( m_Font );
if( pObjStream )
OleSaveToStream( pObjStream, pStm );
// Save our text property out to persistant storage
return m_bstrText.WriteToStream( pStm );
}
STDMETHOD(SetObjectRects)(LPCRECT prcPos,LPCRECT prcClip)
{
IOleInPlaceObjectWindowlessImpl<CAtlEditCtl>::SetObjectRects(prcPos, prcClip);
int cx, cy;
cx = prcPos->right - prcPos->left;
cy = prcPos->bottom - prcPos->top;
::SetWindowPos(m_ctlEdit.m_hWnd, NULL, 0,
0, cx, cy, SWP_NOZORDER | SWP_NOACTIVATE);
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
// Property Handlers
// Our implementation of the stock DISPID_TEXT property. Rather than
// store our property in a CComBSTR variable, we store our property
// in the actual Edit control window itself. However, where we store these
// properties depends on whether the control is in design time mode or run
// time. If design time, we store it in our m_bstrText variable. If run
// time we store the variable in the actual edit control. This mimics
// the behavior of standard Text controls in VB.
STDMETHOD(put_Text)( BSTR Text )
{
USES_CONVERSION;
if( !IsWindow( m_ctlEdit ) )
m_bstrText = Text;
else
m_ctlEdit.SetWindowText( OLE2T( Text ) );
FireViewChange();
return S_OK;
}
STDMETHOD(get_Text)( BSTR* pText )
{
if( !IsWindow( m_ctlEdit ) )
*pText = m_bstrText.Copy();
else
m_ctlEdit.GetWindowText( *pText );
return S_OK;
}
// Our custom error color property
STDMETHOD(put_ErrorColor)( OLE_COLOR Color )
{
m_clrErrorColor = Color;
return S_OK;
}
STDMETHOD(get_ErrorColor)( OLE_COLOR* pColor )
{
*pColor = m_clrErrorColor;
return S_OK;
}
// Our implementation of the Font stock property
STDMETHOD(putref_Font)( IFont* Font )
{
HFONT hFont;
// Release our existing font if there is one (and we are in runtime mode)
if( IsWindow( m_ctlEdit ) && m_Font != NULL )
{
hFont = m_ctlEdit.GetFont();
if( hFont )
m_Font->ReleaseHfont( hFont );
m_Font.Release();
}
// We need to clone this font before storing it in our property
CComPtr<IFont> NewFont;
if( SUCCEEDED( Font->Clone( &NewFont ) ) )
m_Font = NewFont;
OnFontChanged;
FireViewChange();
return S_OK;
}
STDMETHOD(get_Font)( IFont** Font )
{
// Return a reference to our font object
m_Font->AddRef();
*Font = m_Font;
return S_OK;
}
// We need to override the default implementation of put_BackColor
// so that we also set the additional variable m_clrCurrentBackColor
STDMETHOD(put_BackColor)( OLE_COLOR Color )
{
m_clrCurrentBackColor = Color;
m_clrBackColor = Color;
FireOnChanged( DISPID_BACKCOLOR );
FireViewChange();
return S_OK;
}
// Reflect the WM_KEYDOWN VK_TAB message to our container
/*
STDMETHOD(TranslateAccelerator)( LPMSG pMsg )
{
_ASSERTE( FALSE );
if( pMsg->message == WM_KEYDOWN &&
static_cast< TCHAR >( pMsg->wParam ) == VK_TAB )
{
CComQIPtr <IOleControlSite, &IID_IOleControlSite> spSite(m_spClientSite);
BOOL bShift = (GetKeyState(VK_SHIFT) < 0);
BOOL bCtrl = (GetKeyState(VK_CONTROL) < 0);
BOOL bAlt = (GetKeyState(VK_MENU) < 0);
return spSite->TranslateAccelerator( pMsg, (short)(bShift + (bCtrl << 1) + (bAlt << 2)) );
}
return S_FALSE;
}
*/
///////////////////////////////////////////////////////////////////////////
// IViewObjectEx
STDMETHOD(GetViewStatus)(DWORD* pdwStatus)
{
ATLTRACE(_T("IViewObjectExImpl::GetViewStatus\n"));
*pdwStatus = VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE;
return S_OK;
}
// IAtlEditCtl
public:
HRESULT OnDraw(ATL_DRAWINFO& di);
HFONT m_hFontPrev;
HPALETTE m_hPalette;
OLE_COLOR m_clrCurrentBackColor;
OLE_COLOR m_clrErrorColor;
OLE_COLOR m_clrBackColor;
OLE_COLOR m_clrForeColor;
CComBSTR m_bstrText;
CComPtr<IFont> m_Font; // A holder of this control's font object
};
#endif //__ATLEDITCTL_H_